/*!  \file  Map.cpp
 *	  \brief  
 * 
 *   \details   details
 *   \author    Yordan Madzhunkov German Research School for Simulation Sciences GmbH
 *   \version   1.0
 *   \date      04/24/2013 02:56:25 PM
 *   \copyright GNU Public License.
 */

#include <map>
#include <functional>
#include <cstring>
#include <string.h>
#include <assert.h>
#include <iostream>
#include "macros.h"
#include "Map.h"
using namespace std;
struct StrCompare : public std::binary_function<const char*, const char*, bool>{
public:
    bool operator() (const char* str1, const char* str2) const
    { return std::strcmp(str1, str2) < 0; }
};
typedef std::map<const char *, unsigned int, StrCompare> StlMap;

Map::Map() {
	
	names = new const char * [MaxID];
	memset(names, 0, MaxID * sizeof(names[0]));
	data = reinterpret_cast<void*> ( new StlMap());
	iter = reinterpret_cast<void*> ( new StlMap::iterator()) ;
}
Map::~Map() {
	delArr(names);
	StlMap * a = reinterpret_cast<StlMap*>(data);
	delObj(a)
	StlMap::iterator * it =  reinterpret_cast<StlMap::iterator*>(iter);
	iter = 0;
	delObj(it);
}
void Map::insert(const char * name, const unsigned int ID) {
	assert( ID < MaxID);
	StlMap * a = reinterpret_cast<StlMap*>(data);
	if (names[ID]) {
		StlMap::iterator it  = a->find(names[ID]);
	  	a->erase (it); names[ID] = 0;
	}
	a->insert(pair<const char *,unsigned int>(name,ID));
	names[ID] = name;
	// note that if the entry exist it will be overwriten
}
unsigned int Map::insert(const char * name) {
	unsigned int ID = getID(name);
	if (ID < MaxID) {
		return ID;
	} else
		for (unsigned int i = 0; i < MaxID; i++) 
			if (!names[i]) {
				insert(name, i);
				return i;
			}
	return MaxID;
}
unsigned int Map::getID(const char * name) {
	StlMap * a = reinterpret_cast<StlMap*>(data);
	StlMap::iterator it = a->find(name);
	return it != a->end() ? (*it).second : (unsigned int )MaxID;
}
const char * Map::getName(unsigned int ID) {
	assert( ID < MaxID);
	return names[ID];
}
unsigned int Map::first() { // returns the ID of the first entry in the Map
	StlMap::iterator * it =  reinterpret_cast<StlMap::iterator*>(iter);
	StlMap * a = reinterpret_cast<StlMap*>(data);
	*it = a->begin();
	return *it != a->end() ? (*it)->second : (unsigned int ) MaxID;
};
unsigned int Map::next(){ // returns the next entry
	StlMap::iterator * it =  reinterpret_cast<StlMap::iterator*>(iter);
	StlMap * a = reinterpret_cast<StlMap*>(data);
	(*it)++;
	return *it != a->end() ? (*it)->second : (unsigned int ) MaxID;
}; 

#ifndef NDEBUG
#include "UnitTester.h"
UNITTEST(TestMap);
#include <iostream>
using namespace std;
TestMap::TestMap() {
	setName 				("Test Map");
	setDescription  	("Test Map for correct bahaviour & memory allocation");
	setTestAuthor		("Yordan Madzhunkov");
	setDeveloperAuthor("Yordan Madzhunkov");
	setCompileTime(__DATE__, __TIME__); // each class that inherits this one should also have this line.
};
bool TestMap::test() const {
	Map m;
	bool res = true;
	m.insert("abs", 2);
	m.insert("cde", 3);
	res &= m.getName(0 )  == NULL; assert(res);
	res &= m.getName(1 )  == NULL; assert(res);
	res &= m.getName(5 )  == NULL; assert(res);
	res &= m.getName(70)  == NULL; assert(res);
	res &= m.getID("abs") == 2   ; assert(res);
	res &= m.getID("cde") == 3   ; assert(res);
	m.insert("haha", 2);
	res &= m.getID("abs") == Map::MaxID; assert(res);
	res &= m.insert("daka") == 0 ; assert(res);
	// try double inserting something
	res &= m.insert("daka") == 0 ; assert(res);
	res &= m.insert("Daka Baka") == 1; assert(res);
	res &= m.getID("Daka Baka") == 1; assert(res);
	return res;
}
TestMap testMap;
#endif
